#include <bolt.h>
#include <stdlib.h>
#include "pkt_pool.h"

struct pkt_pool {
  int id;
  int use;
  int left;
  TAILQ_HEAD(pp_head, llbuf) pp_head;
};

static struct pkt_pool pkt_pool[PKT_POOL_MAX];

bool pkt_pool_free(int id, struct llbuf *ll)
{
  if (!valid_pkt_pool_id(id))
    return false;
  struct pkt_pool *p = &pkt_pool[id];
  if (!p->use)
    return false;
  ll->pool = id;
  TAILQ_INSERT_TAIL(&p->pp_head, ll, entry);
  p->left++;
  return true;
}

struct llbuf *pkt_pool_alloc(int id)
{
  if (!valid_pkt_pool_id(id))
    return NULL;
  struct pkt_pool *p = &pkt_pool[id];
  if (!p->use)
    return NULL;
  struct llbuf *ll = NULL;
  if (!TAILQ_EMPTY(&p->pp_head)) {
    ll = TAILQ_FIRST(&p->pp_head);
    TAILQ_REMOVE(&p->pp_head, ll, entry); 
    p->left--;
  } else 
    ll = NULL;
  return ll;
}

bool pkt_pool_destroy(int id)
{
  if (!valid_pkt_pool_id(id))
    return false;
  struct pkt_pool *p = &pkt_pool[id];
  while (p->left) {
    struct llbuf *llbuf = pkt_pool_alloc(id);
    if (!llbuf)
      break;
    free(llbuf);
    p->use--;
  }
  return true;
}


bool pkt_pool_create(int id, int num)
{
  if (!valid_pkt_pool_id(id))
    return false;
  struct pkt_pool *p = &pkt_pool[id];
  if (p->use)
    return false;
  p->use = num;
  p->left = 0;
  int   i;
  for (i = 0; i < num /*MAX_LL_QUEUE_ELEMENTS*/; i++) {
    struct llbuf *llbuf = (struct llbuf *) malloc (sizeof (struct llbuf));
    if (llbuf != NULL)
      pkt_pool_free(id, llbuf);
  }
  return true;
}

void pkt_pool_init(void)
{
  int i;
  for (i = 0; i < PKT_POOL_MAX; i++) {  
    struct pkt_pool *p = &pkt_pool[i];
    p->id = i;
    p->use = 0;
    p->left = 0;
    TAILQ_INIT(&p->pp_head);
  }
}

void pkt_pool_deinit(void)
{
  int i;
  for (i = 0; i < PKT_POOL_MAX; i++) {  
    struct pkt_pool *p = &pkt_pool[i];
    if (p->use)
      pkt_pool_destroy(i);
  }
}

BOLT(pkt_pool_release, "packet pool <id> release")
{
  uint32_t id;
  const char *argz = pop_argz();

  if (!str2u32(argz, &id)) {
    printf ("invalid id\n");
    return;
  }
  if (pkt_pool_destroy(id))
    printf ("success\n");
  else
    printf ("failure");
}

BOLT(pkt_pool_create, "packet pool <id> create <number>")
{
  uint32_t id, num;
  const char *argz = pop_argz();

  if (!str2u32(argz, &num)) {
    printf ("invalid num\n");
    return;
  }
  argz = pop_argz();
  if (!str2u32(argz, &id)) {
    printf ("invalid id\n");
    return;
  }
  if (pkt_pool_create(id, num))
    printf ("success\n");
  else
    printf ("failure\n");
}

BOLT(pkt_pool_show, "packet pool show")
{
  int i;
  printf ("%2s %10s %10s\n", "id", "pool-size", "available");
  for (i = 0; i < PKT_POOL_MAX; i++) {
    struct pkt_pool *p = &pkt_pool[i];
    printf ("%2d %10d %8d\n", i, p->use, p->left);
  }
}

BOLT_PROFILE(pool, "", pool_profile, desc)
{
  int i;
  for (i = 0; i < PKT_POOL_MAX; i++) {
    struct pkt_pool *p = &pkt_pool[i];
    if (p && p->use) {
      cmd_load_profile(desc, "packet pool %d create %d", i, p->use);
    }
  }
  cmd_load_profile(desc, "\n");
}



